package org.apache.nutch.web;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteResultHandler;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.ProcessDestroyer;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import cn.data.SysConf;

public class NutchStarter implements Runnable {

	private static final Log log = LogFactory.getLog(NutchStarter.class);

	public static final String NUTCH_EVENT_LISTENER = "nutch.event.listener";

	// private static final String jvmProperty =
	// "-Dhadoop.log.dir=logs -Dhadoop.log.file=hadoop.log";

	private String nutchCrawlParameters = "seeds -dir crawl -depth 3 -topN 10";

	private String WORK_DIR = "/home/admin/spider/spidercrawl";

	private String LIB_DIR = "lib";

	private String CLASSES_DIR = "classes";

	private String LOG_DIR = "logs";

	private String LOG4J_CONFIG = "log4j.properties";

	private ServletContext context;

	private String nutchId;

	private String STD_OUT_LOG = "stdout.log";

	private String STD_ERR_LOG = "stderr.log";

	private String JVM_PARAMETERS = "-Xms256m -Xmx512m";

	public NutchStarter(ServletContext context, String cloneNutchHome, SysConf sysConf, String nutchId)
	{
		this.context = context;
		this.WORK_DIR = cloneNutchHome;
		this.LIB_DIR = FilenameUtils.concat(WORK_DIR, LIB_DIR);
		this.CLASSES_DIR = FilenameUtils.concat(WORK_DIR, CLASSES_DIR);
		this.LOG_DIR = FilenameUtils.concat(WORK_DIR, LOG_DIR);
		this.STD_ERR_LOG = FilenameUtils.concat(WORK_DIR, STD_ERR_LOG);
		this.STD_OUT_LOG = FilenameUtils.concat(WORK_DIR, STD_OUT_LOG);
		this.nutchCrawlParameters = "seeds -dir crawl -depth " + sysConf.getMaxdepth() + " -topN " + sysConf.getMaxlinks();
		this.LOG4J_CONFIG = "file:" + WORK_DIR + "/classes/log4j.properties";
		this.nutchId = nutchId;
	}

	public void run() {
		// delete crawl file
		// deletefile(WORK_DIR + "/crawl");
		log.info("delete crawl files ok!");

		String javaCommand = System.getProperty("java.home") + "/bin/java";
		String separator = System.getProperty("path.separator");
		String fileSeparator = System.getProperty("file.separator");

		List params = new ArrayList<String>();
		// params.add(javaCommand);

		// add jvm parameters
		String[] jvmParamArray = JVM_PARAMETERS.split("\\s");
		for (int i = 0; i < jvmParamArray.length; i++) {
			params.add(jvmParamArray[i]);
		}

		params.add("-Dlog4j.configuration=" + LOG4J_CONFIG);
		params.add("-Dhadoop.log.dir=" + LOG_DIR);
		params.add("-Dhadoop.log.file=hadoop.log");
		params.add("-classpath");
		File dir = new File(LIB_DIR);
		if (dir.isDirectory()) {
			String[] files = dir.list(new FilenameFilter() {
				public boolean accept(File dir, String name) {
					if (name.endsWith(".jar"))
						return true;
					return false;
				}
			});
			String classpath = "";
			for (int i = 0; i < files.length; i++) {
				classpath += (LIB_DIR + fileSeparator + files[i] + separator);
			}
			params.add(classpath + CLASSES_DIR);
		}
		params.add("org.apache.nutch.crawl.Crawl");
		String[] s = nutchCrawlParameters.split("\\s");
		for (int i = 0; i < s.length; i++) {
			params.add(s[i]);
		}
		log.info(params);

		try {
			// use commons exec
			Executor e = new DefaultExecutor();
			e.setWorkingDirectory(new File(WORK_DIR));
			PrintStream out = new PrintStream(
					new FileOutputStream(STD_OUT_LOG), true);
			PrintStream err = new PrintStream(
					new FileOutputStream(STD_ERR_LOG), true);
			e.setStreamHandler(new PumpStreamHandler(out, err));
			ProcessDestroyer pd = new NutchProcessDestroyer();
			// put process destroyer into servlet context for
			// NutchControllerServlet
			// to fire events later
			context.setAttribute(nutchId, pd);
			e.setProcessDestroyer(pd);
			CommandLine c = new CommandLine(javaCommand);
			c.addArguments((String[]) params.toArray(new String[] { null }));

			e.execute(c, new ExecuteResultHandler() {
				public void onProcessComplete(int exitCode) {
					// log.info("job done:" + exitCode);
					context.setAttribute("nutch.crawl.finished", "true");
				}

				public void onProcessFailed(ExecuteException ex) {
					// log.warn("job failed or stopped", ex);
					context.setAttribute("nutch.crawl.finished", "false");
				}
			});
		} catch (ExecuteException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	public static boolean deletefile(String delpath) {
		File file = new File(delpath);
		if (!file.isDirectory()) {
			file.delete();
		} else if (file.isDirectory()) {
			String[] filelist = file.list();
			for (int i = 0; i < filelist.length; i++) {
				File delfile = new File(delpath + "\\" + filelist[i]);
				if (!delfile.isDirectory())
					delfile.delete();
				else if (delfile.isDirectory())
					deletefile(delpath + "\\" + filelist[i]);
			}
			file.delete();
		}
		return true;
	}
}
